package services

import (
	"encoding/json"
	"fmt"
	appConfig "jianianhua-server/config"
	"jianianhua-server/database"
	"jianianhua-server/models"
	"strconv"
	"strings"
	"time"

	"gorm.io/gorm"
)

type AppointmentService struct{}

func NewAppointmentService() *AppointmentService {
	return &AppointmentService{}
}

// CreateAppointmentConfigRequest 创建预约配置请求
type CreateAppointmentConfigRequest struct {
	Date            string `json:"date" binding:"required"`             // 2025-09-06
	StartTime       string `json:"start_time" binding:"required"`       // 09:30
	EndTime         string `json:"end_time" binding:"required"`         // 22:00
	IntervalMinutes int    `json:"interval_minutes" binding:"required"` // 90
	MaxAppointments int    `json:"max_appointments"`                    // 0表示无限制
}

// UpdateAppointmentConfigRequest 更新预约配置请求
type UpdateAppointmentConfigRequest struct {
	StartTime       string `json:"start_time"`
	EndTime         string `json:"end_time"`
	IntervalMinutes int    `json:"interval_minutes"`
	MaxAppointments int    `json:"max_appointments"`
	StaffCount      int    `json:"staff_count"` // 美甲师人数
	Status          int    `json:"status"`
}

// CreateAppointmentRequest 创建预约请求
type CreateAppointmentRequest struct {
	Date            string   `json:"date" binding:"required"` // 2025-09-06
	AppointmentTime string   `json:"appointment_time"`        // 预约时间，可选
	EstimatedTime   string   `json:"estimated_time"`          // 预计到店时间，可选
	QueueNumber     int      `json:"queue_number"`            // 用户选择的排号，可选
	CustomerName    string   `json:"customer_name" binding:"required"`
	CustomerPhone   string   `json:"customer_phone"` // 手机号，根据用户设置决定是否必填
	CustomerRemark  string   `json:"customer_remark"`
	ServiceID       int      `json:"service_id"`    // 服务ID
	ProductTitle    string   `json:"product_title"` // 预约商品标题
	EffectImages    []string `json:"effect_images"` // 效果图URLs
}

// AppointmentResponse 预约响应
type AppointmentResponse struct {
	ID              uint      `json:"id"`
	AppointmentDate string    `json:"appointment_date"`
	AppointmentTime string    `json:"appointment_time"`
	EstimatedTime   time.Time `json:"estimated_time"`
	QueueNumber     int       `json:"queue_number"`
	Status          int       `json:"status"`
	CustomerName    string    `json:"customer_name"`
	CustomerPhone   string    `json:"customer_phone"`
	CustomerRemark  string    `json:"customer_remark"`
	ServiceID       int       `json:"service_id"`    // 服务ID
	ProductTitle    string    `json:"product_title"` // 预约商品标题
	EffectImages    []string  `json:"effect_images"` // 效果图URLs
	// 预约关系信息
	CreatedBy string `json:"created_by,omitempty"` // 创建者姓名
}

// CreateAppointmentConfig 创建预约配置
func (s *AppointmentService) CreateAppointmentConfig(req *CreateAppointmentConfigRequest) (*models.AppointmentConfig, error) {
	// 检查数据库连接
	if database.DB == nil {
		return nil, fmt.Errorf("数据库未连接")
	}
	// 检查日期格式
	if !s.isValidDate(req.Date) {
		return nil, fmt.Errorf("日期格式错误，应为 YYYY-MM-DD")
	}

	// 检查时间格式
	if !s.isValidTime(req.StartTime) || !s.isValidTime(req.EndTime) {
		return nil, fmt.Errorf("时间格式错误，应为 HH:MM")
	}

	// 检查时间逻辑
	if !s.isValidTimeRange(req.StartTime, req.EndTime) {
		return nil, fmt.Errorf("开始时间必须早于结束时间")
	}

	// 检查是否已存在该日期的配置
	var existingConfig models.AppointmentConfig
	err := database.DB.Where("date = ?", req.Date).First(&existingConfig).Error
	if err == nil {
		return nil, fmt.Errorf("该日期的预约配置已存在")
	}

	config := &models.AppointmentConfig{
		Date:            req.Date,
		StartTime:       req.StartTime,
		EndTime:         req.EndTime,
		IntervalMinutes: req.IntervalMinutes,
		MaxAppointments: req.MaxAppointments,
		Status:          1,
	}

	err = database.DB.Create(config).Error
	if err != nil {
		return nil, fmt.Errorf("创建预约配置失败: %v", err)
	}

	return config, nil
}

// UpdateAppointmentConfig 更新预约配置（如果不存在则创建）
func (s *AppointmentService) UpdateAppointmentConfig(date string, req *UpdateAppointmentConfigRequest) (*models.AppointmentConfig, error) {
	var config models.AppointmentConfig
	err := database.DB.Where("date = ?", date).First(&config).Error
	if err != nil {
		// 如果配置不存在，创建一个新的
		config = models.AppointmentConfig{
			Date:            date,
			StartTime:       "09:30", // 默认开始时间
			EndTime:         "22:00", // 默认结束时间
			IntervalMinutes: 90,      // 排队间隔90分钟
			MaxAppointments: 0,       // 默认最大预约数
			Status:          1,       // 默认启用
		}
	}

	// 更新字段
	if req.StartTime != "" {
		if !s.isValidTime(req.StartTime) {
			return nil, fmt.Errorf("开始时间格式错误")
		}
		config.StartTime = req.StartTime
	}

	if req.EndTime != "" {
		if !s.isValidTime(req.EndTime) {
			return nil, fmt.Errorf("结束时间格式错误")
		}
		config.EndTime = req.EndTime
	}

	if req.IntervalMinutes > 0 {
		config.IntervalMinutes = req.IntervalMinutes
	}

	if req.MaxAppointments >= 0 {
		config.MaxAppointments = req.MaxAppointments
	}

	if req.StaffCount > 0 {
		config.StaffCount = req.StaffCount
	}

	// 只有在明确提供status时才更新状态
	if req.Status > 0 {
		config.Status = req.Status
	}

	// 验证时间逻辑
	if !s.isValidTimeRange(config.StartTime, config.EndTime) {
		return nil, fmt.Errorf("开始时间必须早于结束时间")
	}

	err = database.DB.Save(&config).Error
	if err != nil {
		return nil, fmt.Errorf("更新预约配置失败: %v", err)
	}

	return &config, nil
}

// GetAppointmentConfig 获取预约配置
func (s *AppointmentService) GetAppointmentConfig(date string) (*models.AppointmentConfig, error) {
	var config models.AppointmentConfig
	err := database.DB.Where("date = ?", date).First(&config).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, fmt.Errorf("该日期暂不接受预约，请选择其他日期")
		}
		return nil, fmt.Errorf("获取预约配置失败: %v", err)
	}

	return &config, nil
}

// CreateAppointment 创建预约
func (s *AppointmentService) CreateAppointment(userID uint, req *CreateAppointmentRequest) (*AppointmentResponse, error) {
	// 获取该日期的预约配置
	config, err := s.GetAppointmentConfig(req.Date)
	if err != nil {
		return nil, err
	}

	// 检查配置是否启用
	if config.Status != 1 {
		return nil, fmt.Errorf("该日期暂不接受预约，请选择其他日期")
	}

	// 检查是否请假
	if config.IsLeave {
		return nil, fmt.Errorf("该日期已休息，请选择其他日期")
	}

	// 检查最大预约数限制
	if config.MaxAppointments > 0 {
		// 只有当明确设置了最大预约数时才检查限制
		var count int64
		database.DB.Model(&models.Appointment{}).Where("config_id = ? AND status IN (1,2)", config.ID).Count(&count)

		if int(count) >= config.MaxAppointments {
			return nil, fmt.Errorf("今日已约满，请选择其他日期")
		}
	}

	// 使用前端传递的时间，如果没有则计算时间
	var appointmentTime string
	var estimatedTime time.Time
	var queueNumber int

	// 优先使用用户选择的排号
	if req.QueueNumber > 0 {
		queueNumber = req.QueueNumber
		
		// 检查该时间段是否已满（根据美甲师数量）
		staffCount := config.StaffCount
		if staffCount <= 0 {
			staffCount = 1 // 默认1个美甲师
		}
		
		// 查询该时间段（queue_number）的已预约数量（状态为待确认、已确认、已完成）
		var bookedCount int64
		err = database.DB.Model(&models.Appointment{}).
			Where("appointment_date = ? AND queue_number = ? AND status IN (1,2,3)", req.Date, queueNumber).
			Count(&bookedCount).Error
		if err != nil {
			return nil, fmt.Errorf("检查时间段预约状态失败: %v", err)
		}
		
		// 如果该时间段已预约数量达到美甲师数量，则不允许再预约
		if int(bookedCount) >= staffCount {
			return nil, fmt.Errorf("该时间段已约满（%d/%d），请选择其他时间段", int(bookedCount), staffCount)
		}
	} else {
		// 如果没有选择排号，则自动计算
		var count int64
		database.DB.Model(&models.Appointment{}).Where("config_id = ? AND status IN (1,2)", config.ID).Count(&count)
		queueNumber = int(count) + 1
	}

	// 优先使用客户端传递的预计到店时间
	if req.EstimatedTime != "" {
		// 解析客户端传递的预计到店时间 (格式: YYYY-MM-DD HH:MM:SS)
		parsedTime, err := time.Parse("2006-01-02 15:04:05", req.EstimatedTime)
		if err != nil {
			return nil, fmt.Errorf("解析预计到店时间失败: %v", err)
		}
		estimatedTime = parsedTime

		// 如果用户选择了时间，使用用户选择的时间
		if req.AppointmentTime != "" {
			appointmentTime = req.AppointmentTime
		} else {
			// 从预计到店时间中提取时间部分
			appointmentTime = parsedTime.Format("15:04")
		}
	} else if req.AppointmentTime != "" {
		// 用户明确选择了时间，直接使用
		appointmentTime = req.AppointmentTime

		// 计算预计到店时间（基于用户选择的时间）
		appointmentDate, err := time.Parse("2006-01-02", req.Date)
		if err != nil {
			return nil, fmt.Errorf("解析日期失败: %v", err)
		}

		userTime, err := time.Parse("15:04", req.AppointmentTime)
		if err != nil {
			return nil, fmt.Errorf("解析用户选择时间失败: %v", err)
		}

		estimatedTime = appointmentDate.Add(time.Duration(userTime.Hour())*time.Hour +
			time.Duration(userTime.Minute())*time.Minute)
	} else {
		// 用户没有选择时间，使用自动计算
		queueInfo, err := s.calculateQueueInfo(config)
		if err != nil {
			return nil, err
		}
		appointmentTime = queueInfo.AppointmentTime
		estimatedTime = queueInfo.EstimatedTime
		queueNumber = queueInfo.QueueNumber
	}

	// 创建预约记录
	// 处理效果图数据
	var effectImagesJSON string
	if len(req.EffectImages) > 0 {
		effectImagesBytes, err := json.Marshal(req.EffectImages)
		if err != nil {
			return nil, fmt.Errorf("序列化效果图数据失败: %v", err)
		}
		effectImagesJSON = string(effectImagesBytes)
	}

	appointment := &models.Appointment{
		ConfigID:        config.ID,
		UserID:          userID, // 预约创建者
		StaffUserID:     0,      // 分配的美甲师ID，默认为0（未分配）
		AppointmentDate: req.Date,
		AppointmentTime: appointmentTime,
		EstimatedTime:   estimatedTime,
		QueueNumber:     queueNumber,
		Status:          1, // 待确认
		CustomerName:    req.CustomerName,
		CustomerPhone:   req.CustomerPhone,
		CustomerRemark:  req.CustomerRemark,
		ServiceID:       req.ServiceID,
		ProductTitle:    req.ProductTitle,
		EffectImages:    effectImagesJSON,
	}

	err = database.DB.Create(appointment).Error
	if err != nil {
		return nil, fmt.Errorf("创建预约失败: %v", err)
	}

	fmt.Printf("🎯 预约创建成功 - 预约ID: %d, 预约人: %s, 预约日期: %s, 排号: %d\n", 
		appointment.ID, appointment.CustomerName, appointment.AppointmentDate, appointment.QueueNumber)

	// 解析效果图数据
	var effectImages []string
	if appointment.EffectImages != "" {
		err = json.Unmarshal([]byte(appointment.EffectImages), &effectImages)
		if err != nil {
			// 如果解析失败，记录错误但不影响主流程
			// 静默处理解析错误
		}
	}

	// 异步发送管理员通知（不阻塞主流程）
	// 确保每次创建预约都会发送通知，无论是否是第几个
	// 注意：使用副本避免闭包捕获问题
	aptID := appointment.ID
	
	go func(appointmentID uint) {
		// 添加 recover 防止协程 panic
		defer func() {
			if r := recover(); r != nil {
				fmt.Printf("❌ [协程panic] 发送管理员预约通知协程发生panic - 预约ID: %d, 错误: %v\n", appointmentID, r)
			}
		}()
		
		fmt.Printf("📬 启动消息发送协程 - 预约ID: %d\n", appointmentID)
		
		// 延迟一小段时间再发送，避免快速连续创建预约时的频率限制
		// 每次延迟随机时间（100-500ms），避免多个预约同时发送
		time.Sleep(time.Duration(100+appointmentID%400) * time.Millisecond)
		
		// 重新查询完整的预约信息，确保数据最新
		var freshAppointment models.Appointment
		if err := database.DB.Where("id = ?", appointmentID).First(&freshAppointment).Error; err != nil {
			fmt.Printf("⚠️  重新查询预约失败 - 预约ID: %d, 错误: %v\n", appointmentID, err)
			return
		}
		
		fmt.Printf("📋 查询到预约信息 - 预约ID: %d, 预约人: %s, 预约日期: %s\n", 
			freshAppointment.ID, freshAppointment.CustomerName, freshAppointment.AppointmentDate)
		
		cfg := appConfig.LoadConfig()
		if cfg == nil {
			fmt.Printf("❌ 加载配置失败 - 预约ID: %d\n", appointmentID)
			return
		}
		
		messageService := NewWechatMessageService(cfg)
		if messageService == nil {
			fmt.Printf("❌ 创建消息服务失败 - 预约ID: %d\n", appointmentID)
			return
		}
		
		err := messageService.SendAppointmentNotificationToAdmins(&freshAppointment)
		if err != nil {
			// 记录错误但不影响预约创建
			fmt.Printf("❌ 发送管理员预约通知失败 - 预约ID: %d, 预约人: %s, 错误: %v\n", 
				freshAppointment.ID, freshAppointment.CustomerName, err)
		} else {
			fmt.Printf("✅ 成功发送管理员预约通知 - 预约ID: %d, 预约人: %s, 预约日期: %s\n", 
				freshAppointment.ID, freshAppointment.CustomerName, freshAppointment.AppointmentDate)
		}
	}(aptID)

	return &AppointmentResponse{
		ID:              appointment.ID,
		AppointmentDate: appointment.AppointmentDate,
		AppointmentTime: appointment.AppointmentTime,
		EstimatedTime:   appointment.EstimatedTime,
		QueueNumber:     appointment.QueueNumber,
		Status:          appointment.Status,
		CustomerName:    appointment.CustomerName,
		CustomerPhone:   appointment.CustomerPhone,
		CustomerRemark:  appointment.CustomerRemark,
		ServiceID:       appointment.ServiceID,
		ProductTitle:    appointment.ProductTitle,
		EffectImages:    effectImages,
	}, nil
}

// QueueInfo 排队信息
type QueueInfo struct {
	AppointmentTime string
	EstimatedTime   time.Time
	QueueNumber     int
}

// calculateQueueInfo 计算排队信息
func (s *AppointmentService) calculateQueueInfo(config *models.AppointmentConfig) (*QueueInfo, error) {
	// 获取该日期已有的预约数量
	var count int64
	database.DB.Model(&models.Appointment{}).Where("config_id = ? AND status IN (1,2)", config.ID).Count(&count)

	queueNumber := int(count) + 1

	// 计算预约时间
	appointmentTime, estimatedTime, err := s.calculateAppointmentTime(config, queueNumber)
	if err != nil {
		return nil, err
	}

	return &QueueInfo{
		AppointmentTime: appointmentTime,
		EstimatedTime:   estimatedTime,
		QueueNumber:     queueNumber,
	}, nil
}

// calculateAppointmentTime 计算预约时间
func (s *AppointmentService) calculateAppointmentTime(config *models.AppointmentConfig, queueNumber int) (string, time.Time, error) {
	// 解析开始时间
	startTime, err := time.Parse("15:04", config.StartTime)
	if err != nil {
		return "", time.Time{}, fmt.Errorf("解析开始时间失败: %v", err)
	}

	// 解析结束时间
	endTime, err := time.Parse("15:04", config.EndTime)
	if err != nil {
		return "", time.Time{}, fmt.Errorf("解析结束时间失败: %v", err)
	}

	// 解析日期
	appointmentDate, err := time.Parse("2006-01-02", config.Date)
	if err != nil {
		return "", time.Time{}, fmt.Errorf("解析日期失败: %v", err)
	}

	// 计算预约时间（第一个人是开始时间，后面的人按间隔递增）
	minutesToAdd := (queueNumber - 1) * config.IntervalMinutes
	appointmentDateTime := appointmentDate.Add(time.Duration(startTime.Hour())*time.Hour +
		time.Duration(startTime.Minute())*time.Minute +
		time.Duration(minutesToAdd)*time.Minute)

	// 明确设置为本地时区，避免时区转换问题
	appointmentDateTime = time.Date(appointmentDateTime.Year(), appointmentDateTime.Month(), appointmentDateTime.Day(),
		appointmentDateTime.Hour(), appointmentDateTime.Minute(), appointmentDateTime.Second(), 0, time.Local)

	// 计算结束时间
	endDateTime := appointmentDate.Add(time.Duration(endTime.Hour())*time.Hour +
		time.Duration(endTime.Minute())*time.Minute)

	// 明确设置为本地时区，避免时区转换问题
	endDateTime = time.Date(endDateTime.Year(), endDateTime.Month(), endDateTime.Day(),
		endDateTime.Hour(), endDateTime.Minute(), endDateTime.Second(), 0, time.Local)

	// 检查预约时间是否超过营业时间
	if appointmentDateTime.After(endDateTime) || appointmentDateTime.Equal(endDateTime) {
		return "", time.Time{}, fmt.Errorf("今日已约满，请选择其他日期")
	}

	// 格式化预约时间
	appointmentTimeStr := appointmentDateTime.Format("15:04")

	return appointmentTimeStr, appointmentDateTime, nil
}

// GetAppointments 获取预约列表
func (s *AppointmentService) GetAppointments(userID uint, date string) ([]AppointmentResponse, int64, error) {
	// 获取用户信息
	var user models.User
	err := database.DB.Where("id = ?", userID).First(&user).Error
	if err != nil {
		return nil, 0, fmt.Errorf("获取用户信息失败: %v", err)
	}

	// 检查是否为管理员
	isAdmin, err := s.isAdmin(userID)
	if err != nil {
		return nil, 0, fmt.Errorf("检查管理员权限失败: %v", err)
	}

	var query *gorm.DB
	if isAdmin {
		// 管理员可以看到所有预约
		query = database.DB.Model(&models.Appointment{})
	} else {
		// 普通用户只能看到自己创建的预约
		query = database.DB.Model(&models.Appointment{}).Where("user_id = ?", userID)
	}

	if date != "" {
		query = query.Where("appointment_date = ?", date)
	}

	var total int64
	query.Count(&total)

	// 返回所有数据，不分页
	var appointments []models.Appointment
	err = query.Preload("Config").Preload("User").Order("appointment_date DESC, queue_number DESC").Find(&appointments).Error
	if err != nil {
		return nil, 0, err
	}


	var responses []AppointmentResponse
	for _, apt := range appointments {
		createdBy := ""
		if apt.User != nil {
			createdBy = apt.User.Nickname
		}

		// 解析效果图数据
		var effectImages []string
		if apt.EffectImages != "" {
			err := json.Unmarshal([]byte(apt.EffectImages), &effectImages)
			if err != nil {
				// 如果解析失败，记录错误但不影响主流程
				// 静默处理解析错误
			}
		}

		responses = append(responses, AppointmentResponse{
			ID:              apt.ID,
			AppointmentDate: apt.AppointmentDate,
			AppointmentTime: apt.AppointmentTime,
			EstimatedTime:   apt.EstimatedTime,
			QueueNumber:     apt.QueueNumber,
			Status:          apt.Status,
			CustomerName:    apt.CustomerName,
			CustomerPhone:   apt.CustomerPhone,
			CustomerRemark:  apt.CustomerRemark,
			ServiceID:       apt.ServiceID,
			ProductTitle:    apt.ProductTitle,
			EffectImages:    effectImages,
			CreatedBy:       createdBy,
		})
	}

	return responses, total, nil
}

// 工具函数
func (s *AppointmentService) isValidDate(date string) bool {
	_, err := time.Parse("2006-01-02", date)
	return err == nil
}

func (s *AppointmentService) isValidTime(timeStr string) bool {
	_, err := time.Parse("15:04", timeStr)
	return err == nil
}

func (s *AppointmentService) isValidTimeRange(startTime, endTime string) bool {
	start, err1 := time.Parse("15:04", startTime)
	end, err2 := time.Parse("15:04", endTime)

	if err1 != nil || err2 != nil {
		return false
	}

	return start.Before(end)
}

// isAdmin 检查用户是否为管理员
func (s *AppointmentService) isAdmin(userID uint) (bool, error) {
	var user models.User
	err := database.DB.Where("id = ?", userID).First(&user).Error
	if err != nil {
		return false, err
	}

	// 检查用户角色是否为admin
	return user.Role == "admin", nil
}

// UpdateAppointmentStatus 更新预约状态
func (s *AppointmentService) UpdateAppointmentStatus(appointmentID string, status int, userID uint, cancelReason string) (*models.Appointment, error) {
	// 将字符串ID转换为uint
	id, err := strconv.ParseUint(appointmentID, 10, 32)
	if err != nil {
		return nil, fmt.Errorf("无效的预约ID")
	}

	// 查找预约记录
	var appointment models.Appointment
	err = database.DB.Where("id = ?", uint(id)).First(&appointment).Error
	if err != nil {
		return nil, fmt.Errorf("预约记录不存在")
	}

	// 检查权限：只有管理员或预约创建者可以更新状态
	isAdmin, err := s.isAdmin(userID)
	if err != nil {
		return nil, fmt.Errorf("权限检查失败")
	}

	if !isAdmin && appointment.UserID != userID {
		return nil, fmt.Errorf("无权限更新此预约")
	}

	// 更新状态和取消原因（如果提供）
	updateData := map[string]interface{}{
		"status": status,
	}
	if status == 4 && cancelReason != "" {
		updateData["cancel_reason"] = cancelReason
	}
	
	err = database.DB.Model(&appointment).Updates(updateData).Error
	if err != nil {
		return nil, fmt.Errorf("更新预约状态失败")
	}

	// 如果状态更新为取消（status = 4）
	if status == 4 {
		// 重新查询完整的预约信息（包括关联数据）
		var updatedAppointment models.Appointment
		database.DB.Where("id = ?", uint(id)).First(&updatedAppointment)
		
		if !isAdmin {
			// 用户自己取消预约，给管理员发消息
			fmt.Printf("📧 用户自己取消预约，向管理员发送通知 - 预约ID: %d, 用户ID: %d\n", updatedAppointment.ID, userID)
			
			go func(apt models.Appointment) {
				// 添加 recover 防止协程 panic
				defer func() {
					if r := recover(); r != nil {
						fmt.Printf("❌ [协程panic] 发送管理员取消预约通知协程发生panic - 预约ID: %d, 错误: %v\n", apt.ID, r)
					}
				}()
				
				fmt.Printf("📬 [用户取消] 启动消息发送协程 - 预约ID: %d\n", apt.ID)
				
				cfg := appConfig.LoadConfig()
				if cfg == nil {
					fmt.Printf("❌ 加载配置失败 - 预约ID: %d\n", apt.ID)
					return
				}
				
				messageService := NewWechatMessageService(cfg)
				if messageService == nil {
					fmt.Printf("❌ 创建消息服务失败 - 预约ID: %d\n", apt.ID)
					return
				}
				
				err := messageService.SendCancelNotificationToAdmins(&apt)
				if err != nil {
					// 记录错误但不影响主流程
					fmt.Printf("❌ 发送管理员取消预约通知失败 - 预约ID: %d, 错误: %v\n", apt.ID, err)
				} else {
					fmt.Printf("✅ 成功发送管理员取消预约通知 - 预约ID: %d\n", apt.ID)
				}
			}(updatedAppointment)
		} else {
			// 管理员取消预约，给顾客发消息
			reason := cancelReason
			if reason == "" {
				reason = "管理员取消"
			}
			
			go func(apt models.Appointment, cancelReason string) {
				// 添加 recover 防止协程 panic
				defer func() {
					if r := recover(); r != nil {
						fmt.Printf("❌ [协程panic] 发送用户取消预约通知协程发生panic - 预约ID: %d, 错误: %v\n", apt.ID, r)
					}
				}()
				
				fmt.Printf("📬 [管理员取消订单] 启动消息发送协程 - 预约ID: %d\n", apt.ID)
				
				// 重新查询完整的预约信息，确保数据最新
				var freshAppointment models.Appointment
				if err := database.DB.Where("id = ?", apt.ID).First(&freshAppointment).Error; err != nil {
					fmt.Printf("⚠️  [管理员取消订单] 重新查询预约失败 - 预约ID: %d, 错误: %v\n", apt.ID, err)
					return
				}
				
				fmt.Printf("📋 [管理员取消订单] 查询到预约信息 - 预约ID: %d, 预约人: %s, 预约日期: %s, 用户ID: %d\n", 
					freshAppointment.ID, freshAppointment.CustomerName, freshAppointment.AppointmentDate, freshAppointment.UserID)
				
				cfg := appConfig.LoadConfig()
				if cfg == nil {
					fmt.Printf("❌ 加载配置失败 - 预约ID: %d\n", apt.ID)
					return
				}
				
				messageService := NewWechatMessageService(cfg)
				if messageService == nil {
					fmt.Printf("❌ 创建消息服务失败 - 预约ID: %d\n", apt.ID)
					return
				}
				
				err := messageService.SendCancelNotification(&freshAppointment, cancelReason)
				if err != nil {
					// 记录错误但不影响主流程
					fmt.Printf("❌ [管理员取消订单] 发送取消预约通知失败 - 预约ID: %d, 错误: %v\n", freshAppointment.ID, err)
				} else {
					fmt.Printf("✅ [管理员取消订单] 成功发送取消预约通知 - 预约ID: %d, 预约人: %s\n", 
						freshAppointment.ID, freshAppointment.CustomerName)
				}
			}(updatedAppointment, reason)
		}
	}

	return &appointment, nil
}

// UpdateAppointmentEstimatedTime 更新预约预计到店时间
func (s *AppointmentService) UpdateAppointmentEstimatedTime(appointmentID string, estimatedTime string, userID uint) (*models.Appointment, error) {
	// 将字符串ID转换为uint
	id, err := strconv.ParseUint(appointmentID, 10, 32)
	if err != nil {
		return nil, fmt.Errorf("无效的预约ID")
	}

	// 查找预约记录
	var appointment models.Appointment
	err = database.DB.Where("id = ?", uint(id)).First(&appointment).Error
	if err != nil {
		return nil, fmt.Errorf("预约记录不存在")
	}

	// 检查权限：只有管理员或预约创建者可以更新时间
	isAdmin, err := s.isAdmin(userID)
	if err != nil {
		return nil, fmt.Errorf("权限检查失败")
	}

	if !isAdmin && appointment.UserID != userID {
		return nil, fmt.Errorf("无权限更新此预约")
	}

	// 解析时间 (支持多种格式)
	var parsedTime time.Time
	var parseErr error

	// 尝试解析 RFC3339 格式
	parsedTime, parseErr = time.Parse(time.RFC3339, estimatedTime)
	if parseErr != nil {
		// 尝试解析 YYYY-MM-DD HH:MM:SS 格式
		parsedTime, parseErr = time.Parse("2006-01-02 15:04:05", estimatedTime)
		if parseErr != nil {
			return nil, fmt.Errorf("无效的时间格式，支持格式：RFC3339 或 YYYY-MM-DD HH:MM:SS")
		}
	}

	// 更新预计到店时间
	appointment.EstimatedTime = parsedTime
	err = database.DB.Save(&appointment).Error
	if err != nil {
		return nil, fmt.Errorf("更新预计到店时间失败")
	}

	return &appointment, nil
}

// ToggleLeaveStatus 切换请假状态
func (s *AppointmentService) ToggleLeaveStatus(date string, isLeave bool, leaveReason string, userID uint) (*models.AppointmentConfig, error) {
	// 检查权限：只有管理员可以设置请假状态
	isAdmin, err := s.isAdmin(userID)
	if err != nil {
		return nil, fmt.Errorf("权限检查失败")
	}

	if !isAdmin {
		return nil, fmt.Errorf("只有管理员可以设置请假状态")
	}

	// 查找或创建预约配置
	var config models.AppointmentConfig
	err = database.DB.Where("date = ?", date).First(&config).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			// 如果配置不存在，创建一个默认配置
			config = models.AppointmentConfig{
				Date:            date,
				StartTime:       "09:30",
				EndTime:         "22:00",
				IntervalMinutes: 90,
				MaxAppointments: 0,
				Status:          1,
				IsLeave:         isLeave,
				LeaveReason:     leaveReason,
			}
			err = database.DB.Create(&config).Error
			if err != nil {
				return nil, fmt.Errorf("创建预约配置失败")
			}
		} else {
			return nil, fmt.Errorf("查询预约配置失败")
		}
	} else {
		// 更新现有配置的请假状态
		config.IsLeave = isLeave
		config.LeaveReason = leaveReason
		err = database.DB.Save(&config).Error
		if err != nil {
			return nil, fmt.Errorf("更新请假状态失败")
		}
	}

	return &config, nil
}

// GetAppointmentConfigByDate 根据日期获取预约配置
func (s *AppointmentService) GetAppointmentConfigByDate(date string) (*models.AppointmentConfig, error) {
	var config models.AppointmentConfig
	err := database.DB.Where("date = ?", date).First(&config).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			// 如果配置不存在，返回默认配置
			return &models.AppointmentConfig{
				Date:            date,
				StartTime:       "09:30",
				EndTime:         "22:00",
				IntervalMinutes: 90,
				MaxAppointments: 0,
				StaffCount:      1,
				Status:          1,
				IsLeave:         false,
				LeaveReason:     "",
			}, nil
		}
		return nil, fmt.Errorf("查询预约配置失败")
	}

	return &config, nil
}

// CheckLeaveStatus 检查指定日期是否请假
func (s *AppointmentService) CheckLeaveStatus(date string) (bool, error) {
	config, err := s.GetAppointmentConfigByDate(date)
	if err != nil {
		return false, err
	}
	return config.IsLeave, nil
}

// BookedTimeSlotsResponse 已预约时间段响应结构
type BookedTimeSlotsResponse struct {
	BookedCounts map[int]int `json:"booked_counts"` // queue_number -> 已预约数量
	StaffCount   int         `json:"staff_count"`    // 美甲师人数
}

// GetBookedTimeSlots 获取指定日期已预约的时间段（返回每个时间段的已预约数量）
func (s *AppointmentService) GetBookedTimeSlots(date string) (*BookedTimeSlotsResponse, error) {
	// 获取该日期的预约配置，获取美甲师人数
	config, err := s.GetAppointmentConfigByDate(date)
	if err != nil {
		return nil, fmt.Errorf("获取预约配置失败: %v", err)
	}

	staffCount := config.StaffCount
	if staffCount <= 0 {
		staffCount = 1 // 默认1个美甲师
	}

	// 查询该日期所有已预约的排号（状态为待确认、已确认、已完成）
	type SlotCount struct {
		QueueNumber int
		Count       int64
	}
	var slotCounts []SlotCount
	err = database.DB.Model(&models.Appointment{}).
		Select("queue_number, COUNT(*) as count").
		Where("appointment_date = ? AND status IN (1,2,3) AND queue_number > 0", date).
		Group("queue_number").
		Scan(&slotCounts).Error
	if err != nil {
		return nil, fmt.Errorf("查询已预约排号失败: %v", err)
	}

	// 构建 map: queue_number -> 已预约数量
	bookedCounts := make(map[int]int)
	for _, sc := range slotCounts {
		bookedCounts[sc.QueueNumber] = int(sc.Count)
	}


	return &BookedTimeSlotsResponse{
		BookedCounts: bookedCounts,
		StaffCount:   staffCount,
	}, nil
}

// timeToMinutes 将时间字符串转换为分钟数
func (s *AppointmentService) timeToMinutes(timeStr string) int {
	parts := strings.Split(timeStr, ":")
	hours, _ := strconv.Atoi(parts[0])
	minutes, _ := strconv.Atoi(parts[1])
	return hours*60 + minutes
}

// minutesToTime 将分钟数转换为时间字符串
func (s *AppointmentService) minutesToTime(minutes int) string {
	hours := minutes / 60
	mins := minutes % 60
	return fmt.Sprintf("%02d:%02d", hours, mins)
}

// CancelAppointmentsByDate 取消指定日期的所有预约
func (s *AppointmentService) CancelAppointmentsByDate(date string, reason string, userID uint) (map[string]interface{}, error) {
	// 检查用户是否为管理员
	isAdmin, err := s.isAdmin(userID)
	if err != nil {
		return nil, fmt.Errorf("权限检查失败")
	}
	if !isAdmin {
		return nil, fmt.Errorf("无权限执行此操作")
	}

	// 查找指定日期的所有预约
	var appointments []models.Appointment
	err = database.DB.Where("appointment_date = ? AND status IN (?)", date, []int{1, 2, 3}).Find(&appointments).Error
	if err != nil {
		return nil, fmt.Errorf("查询预约失败")
	}

	// 批量更新预约状态为已取消
	if len(appointments) > 0 {
		// 获取所有预约ID，用于精确更新
		appointmentIDs := make([]uint, len(appointments))
		for i, appointment := range appointments {
			appointmentIDs[i] = appointment.ID
		}

		err = database.DB.Model(&models.Appointment{}).
			Where("id IN (?)", appointmentIDs).
			Updates(map[string]interface{}{
				"status":        4, // 已取消
				"cancel_reason": reason,
			}).Error
		if err != nil {
			return nil, fmt.Errorf("更新预约状态失败")
		}

		// 发送订阅消息通知用户
		go s.sendCancelNotifications(appointments, reason)
	}

	return map[string]interface{}{
		"date":            date,
		"cancelled_count": len(appointments),
		"reason":          reason,
	}, nil
}

// sendCancelNotifications 发送取消通知
func (s *AppointmentService) sendCancelNotifications(appointments []models.Appointment, reason string) {
	// 创建微信消息服务
	cfg := appConfig.LoadConfig()
	messageService := NewWechatMessageService(cfg)

	for _, appointment := range appointments {
		// 发送微信订阅消息
		messageService.SendCancelNotification(&appointment, reason)
	}
}

// GetAvailableDates 获取所有可用的预约日期
func (s *AppointmentService) GetAvailableDates() ([]string, error) {
	var configs []models.AppointmentConfig

	// 查询所有状态为1（启用）的配置，不判断请假状态
	err := database.DB.Where("status = ?", 1).Find(&configs).Error
	if err != nil {
		return nil, fmt.Errorf("查询可用日期失败: %v", err)
	}

	var dates []string
	for _, config := range configs {
		dates = append(dates, config.Date)
	}

	return dates, nil
}

// SetGlobalStaffCount 设置全局美甲师人数（批量更新所有日期的配置）
func (s *AppointmentService) SetGlobalStaffCount(staffCount int, userID uint) error {
	// 检查用户是否为管理员
	isAdmin, err := s.isAdmin(userID)
	if err != nil {
		return fmt.Errorf("权限检查失败")
	}
	if !isAdmin {
		return fmt.Errorf("无权限执行此操作")
	}

	if staffCount <= 0 {
		return fmt.Errorf("美甲师人数必须大于0")
	}

	// 批量更新所有预约配置的美甲师人数
	// 使用 Where("1 = 1") 来更新所有记录，避免 GORM 的 WHERE 条件检查
	err = database.DB.Model(&models.AppointmentConfig{}).
		Where("1 = 1").
		Update("staff_count", staffCount).Error
	if err != nil {
		return fmt.Errorf("更新美甲师人数失败: %v", err)
	}

	return nil
}

// GetGlobalStaffCount 获取全局美甲师人数（从最新的配置中获取）
func (s *AppointmentService) GetGlobalStaffCount() (int, error) {
	var config models.AppointmentConfig
	err := database.DB.Order("updated_at DESC").First(&config).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return 1, nil // 默认1个美甲师
		}
		return 0, fmt.Errorf("查询美甲师人数失败: %v", err)
	}

	staffCount := config.StaffCount
	if staffCount <= 0 {
		staffCount = 1 // 默认1个美甲师
	}

	return staffCount, nil
}
